home *** CD-ROM | disk | FTP | other *** search
/ AI Game Programming Wisdom / AIGameProgrammingWisdom.iso / SourceCode / 11 Learning / 01 Manslow / GAPBILExample / CGA.cpp next >
Encoding:
C/C++ Source or Header  |  2001-10-09  |  10.1 KB  |  421 lines

  1. //GAPBILExample
  2. //Copyright John Manslow
  3. //29/09/2001
  4.  
  5. ////////////////////////////////////////////////////
  6. //Remove this include if not compiling under Windows
  7. #include "stdafx.h"
  8. #define new DEBUG_NEW
  9. ////////////////////////////////////////////////////
  10.  
  11. #include "CGA.h"
  12. #include "assert.h"
  13. #include "fstream.h"
  14.  
  15. CGA::CGA(
  16.          const unsigned long    ulNewPopulationSize,
  17.          const unsigned long    ulNewChromosomeLength,
  18.          const int * const            pnNewGeneTypes
  19.          )
  20. {
  21.     unsigned long i;
  22.  
  23.     //Use asserrts to check the validity of the parameters
  24.     assert(!(ulNewPopulationSize<1));
  25.     ulPopulationSize=ulNewPopulationSize;
  26.  
  27.     assert(!(ulNewChromosomeLength<1));
  28.     ulChromosomeLength=ulNewChromosomeLength;
  29.  
  30.     //Default values of the mutation and crossover probabilities gives an average of one mutation and
  31.     //crossover per mating
  32.     dMutationRate=1.0/double(ulChromosomeLength);
  33.     dCrossoverRate=1.0/double(ulChromosomeLength);
  34.  
  35.     //Allocate memory to store the population and fitnesses, etc.
  36.     AllocateMemory();
  37.  
  38.     //Record the types of each gene
  39.     for (i=0;i<ulChromosomeLength;i++)
  40.     {
  41.         pnGeneTypes[i]=pnNewGeneTypes[i];
  42.     }
  43.  
  44.     //And initialise the population with random individuals
  45.     InitialisePopulation();
  46. }
  47.  
  48. CGA::~CGA()
  49. {
  50.     //Deallocate memory!
  51.     DeallocateMemory();
  52. }
  53.  
  54. void CGA::AllocateMemory(void)
  55. {
  56.     unsigned long i;
  57.  
  58.     //An array to store the type of each gene. Genes can be either binary (type 0) or real (type 1)
  59.     pnGeneTypes=new int[ulChromosomeLength];
  60.  
  61.     //Store the actual genes of the population
  62.     ppdGenes=new double*[ulPopulationSize];
  63.     for (i=0;i<ulPopulationSize;i++)
  64.     {
  65.         //(each individual n the population is one chromosme)
  66.         ppdGenes[i]=new double[ulChromosomeLength];
  67.     }
  68.  
  69.     //An array to store the fitnesses of members of the population
  70.     pdFitnesses=new double[ulPopulationSize];
  71.  
  72.     //Space to store a copy of the best individual found so far
  73.     pdBestChromosome=new double[ulChromosomeLength];
  74. }
  75.  
  76. void CGA::DeallocateMemory(void)
  77. {
  78.     unsigned long i;
  79.  
  80.     //Deallocate everything
  81.     delete []pnGeneTypes;
  82.     delete []pdFitnesses;
  83.     delete []pdBestChromosome;
  84.  
  85.     for (i=0;i<ulPopulationSize;i++)
  86.     {
  87.         delete []ppdGenes[i];
  88.     }
  89.     delete []ppdGenes;
  90. }
  91.  
  92. void CGA::InitialisePopulation(void)
  93. {
  94.     unsigned long i,j;
  95.  
  96.     //Since this effectively resets any evolution that has occured, we might as well set the iteration counter
  97.     ulIteration=0;
  98.  
  99.     //Also set the best fitness to a large negative value so that it will be overwritten immediately. Of
  100.     //course, make sure that no fitness evaluations can result in fitnesses more negative than this
  101.     dBestFitness=-1e+100;
  102.  
  103.     //Initialise the population and the fitness statistics of its individual members
  104.     for (i=0;i<ulPopulationSize;i++)
  105.     {
  106.         //Set the recorded fitnesses of all members of the population to zero. These values are never used,
  107.         //so could be almost anything (see SetFitness function)
  108.         pdFitnesses[i]=0.0;
  109.  
  110.         //Sets the genes of the ith chromosome to random values
  111.         for (j=0;j<ulChromosomeLength;j++)
  112.         {
  113.             if(pnGeneTypes[j]==0)
  114.             {
  115.                 //If this gene is binary set it to either 0 or 1
  116.                 ppdGenes[i][j]=double(rand()%2);
  117.             }
  118.             else
  119.             {
  120.                 //Otherwise, set it to a random value between 0 and 1
  121.                 ppdGenes[i][j]=double(rand())/double(RAND_MAX);
  122.             }
  123.         }
  124.     }
  125. }
  126.  
  127. void CGA::Mutate(double * const pdGenes)
  128. {
  129.     unsigned long i;
  130.  
  131.     //Make sure the argument is valid
  132.     assert(pdGenes);
  133.  
  134.     //For every gene in the chromosome
  135.     for (i=0;i<ulChromosomeLength;i++)
  136.     {
  137.         //Do we want to mutate this gene?
  138.         if(double(rand())/double(RAND_MAX)<dMutationRate)
  139.         {
  140.             //If so
  141.             if(pnGeneTypes[i]==0)
  142.             {
  143.                 //If the gene is binary, flip the bit
  144.                 pdGenes[i]=1.0-pdGenes[i];
  145.             }
  146.             else
  147.             {
  148.                 //If the gene is real, perturb it
  149.                 pdGenes[i]=double(rand())/double(RAND_MAX);
  150.             }
  151.         }
  152.     }
  153. }
  154.  
  155. void CGA::Crossover(
  156.                     const double * const pdParentA, 
  157.                     const double * const pdParentB,
  158.                     const unsigned long ulLocationForChild
  159.                     )
  160. {
  161.     unsigned long i;
  162.  
  163.     //We'll use this array to mark locations for crossover
  164.     int *pnCrossoverSites=new int[ulChromosomeLength];
  165.     int nParentSelector;
  166.  
  167.     //Prepare storage for teh child
  168.     double *pdChild=new double[ulChromosomeLength];
  169.  
  170.     //For every gene
  171.     for(i=0;i<ulChromosomeLength;i++)
  172.     {
  173.         //Decide whether it'll be a crossover site
  174.         if(double(rand())/double(RAND_MAX)<dCrossoverRate)
  175.         {
  176.             //If so, mark it with a one
  177.             pnCrossoverSites[i]=1;
  178.         }
  179.         else
  180.         {
  181.             //Otherwise, mark it with a zero
  182.             pnCrossoverSites[i]=0;
  183.         }
  184.     }
  185.  
  186.     //This variable selects which parent genes in the child will come from. Initially, they will come from the first
  187.     //parent
  188.     nParentSelector=0;
  189.  
  190.     //For each gene in the child
  191.     for(i=0;i<ulChromosomeLength;i++)
  192.     {
  193.         //If we're copying this gene from the first parent
  194.         if (nParentSelector==0)
  195.         {
  196.             //Copy it
  197.             pdChild[i]=pdParentA[i];
  198.         }
  199.         else
  200.         {
  201.             //Otherwise, copy it from the other parent
  202.             pdChild[i]=pdParentB[i];
  203.         }
  204.  
  205.         //If this is a crossover site
  206.         if(pnCrossoverSites[i]==1)
  207.         {
  208.             //Change the parent selector to copy genes from the other parent
  209.             nParentSelector=1-nParentSelector;
  210.         }
  211.     }
  212.  
  213.     //Delete the chromosome that the child will replace in the population
  214.     delete []ppdGenes[ulLocationForChild];
  215.  
  216.     //Delete the crossover site markers
  217.     delete []pnCrossoverSites;
  218.  
  219.     //Put the new chromosome into the population in the specified location
  220.     ppdGenes[ulLocationForChild]=pdChild;
  221. }
  222.  
  223. void CGA::Mate(void)
  224. {
  225.     unsigned long ulParentA,ulParentB;
  226.  
  227.     //Choose two parents randomly form the populaiton
  228.     ulParentA=rand()%ulPopulationSize;
  229.     ulParentB=rand()%ulPopulationSize;
  230.  
  231.     //If they're the same
  232.     while(ulParentA==ulParentB)
  233.     {
  234.         //Re-choose parent the second parent
  235.         ulParentB=rand()%ulPopulationSize;
  236.     }
  237.  
  238.     //We'll want to replace the least fit of the parents with the child, so if parent A is fittest,
  239.     if (pdFitnesses[ulParentA]>pdFitnesses[ulParentB])
  240.     {
  241.         //Create the child by crossover, and replace parent B with it in the population
  242.         Crossover(ppdGenes[ulParentA],ppdGenes[ulParentB],ulParentB);
  243.  
  244.         //Set the working chromosome to the position of the child in the population (so that when 
  245.         //SetFitness is called we'll know which individual it is referring to).
  246.         ulWorkingChromosome=ulParentB;
  247.     }
  248.     else
  249.     {
  250.         //If parent B was fittest, create a child by crossover and replace parent A
  251.         Crossover(ppdGenes[ulParentA],ppdGenes[ulParentB],ulParentA);
  252.         ulWorkingChromosome=ulParentA;
  253.     }
  254.  
  255.     //Mutate the child
  256.     Mutate(ppdGenes[ulWorkingChromosome]);
  257. }
  258.  
  259. double *CGA::pdGetChromosomeForEvaluation(void)
  260. {
  261.     //This and SetFitness are the only functions that need to be called to make the GA work.
  262.     unsigned long i;
  263.     
  264.     //If we've not yet evaluated every individual in the population at least once,
  265.     if (ulIteration<ulPopulationSize)
  266.     {
  267.         //Prepare to evaluate the fitness of the ulIteration member of the population
  268.         ulWorkingChromosome=ulIteration;
  269.     }
  270.     else
  271.     {
  272.         //Otherwise, create a new individual and place it in the population ready to be evaluated
  273.         Mate();
  274.     }
  275.  
  276.     //Prepare some storage for a copy of the new chromosome so that it can be returned to the calling
  277.     //function and its fitness evaluated
  278.     double *pdChromosomeForEvaluation=new double[ulChromosomeLength];
  279.     for (i=0;i<ulChromosomeLength;i++)
  280.     {
  281.         //Copy the new chromosome
  282.         pdChromosomeForEvaluation[i]=ppdGenes[ulWorkingChromosome][i];
  283.     }
  284.  
  285.     //Return it
  286.     return pdChromosomeForEvaluation;
  287. }
  288.     
  289. void CGA::SetFitness(const double dNewFitness)
  290. {
  291.     //This is the only other function that needs to be called and is used to set the fitness of a chromosome
  292.     //that has just been evaluated
  293.  
  294.     //Actually set the chromosome's fitness
  295.     pdFitnesses[ulWorkingChromosome]=dNewFitness;
  296.  
  297.     //If the fitness is higher than anything else yet achieved
  298.     if(dNewFitness>dBestFitness)
  299.     {
  300.         //Record it
  301.         dBestFitness=dNewFitness;
  302.         unsigned long i;
  303.  
  304.         //And keep a copy of the chromosome
  305.         for(i=0;i<ulChromosomeLength;i++)
  306.         {
  307.             pdBestChromosome[i]=ppdGenes[ulWorkingChromosome][i];
  308.         }
  309.     }
  310.  
  311.     //Record another fitness evaluation
  312.     ulIteration++;
  313. }
  314.  
  315. double *CGA::pdGetBestChromosome(void)
  316. {
  317.     //Returns a pointer to the best chromosome discovered so far. Don't delete!
  318.     return pdBestChromosome;
  319. }
  320.  
  321. double CGA::dGetBestPerformance(void)
  322. {
  323.     //Return the best fitness achieved so far
  324.     return dBestFitness;
  325. }
  326.  
  327. int CGA::Save(const char * const psFilename)
  328. {
  329.     //Saves the status of the GA
  330.     ofstream *pOut=new ofstream(psFilename);
  331.     unsigned long i,j;
  332.     if(!pOut || !pOut->is_open())
  333.     {
  334.         return 0;
  335.     }
  336.     pOut->precision(18);
  337.     *pOut<<ulPopulationSize;
  338.     *pOut<<"\n";
  339.     *pOut<<ulChromosomeLength;
  340.     *pOut<<"\n";
  341.     *pOut<<dMutationRate;
  342.     *pOut<<"\n";
  343.     *pOut<<dCrossoverRate;
  344.     *pOut<<"\n";
  345.     *pOut<<ulIteration;
  346.     *pOut<<"\n";
  347.     *pOut<<ulWorkingChromosome;
  348.     *pOut<<"\n";
  349.     for (i=0;i<ulChromosomeLength;i++)
  350.     {
  351.         *pOut<<pnGeneTypes[i];
  352.         *pOut<<"\t";
  353.     }
  354.     *pOut<<"\n";
  355.     for (i=0;i<ulPopulationSize;i++)
  356.     {
  357.         for (j=0;j<ulChromosomeLength;j++)
  358.         {
  359.             *pOut<<ppdGenes[i][j];
  360.             *pOut<<"\t";
  361.         }
  362.         *pOut<<pdFitnesses[i];
  363.         *pOut<<"\n";
  364.     }
  365.     *pOut<<dBestFitness;
  366.     *pOut<<"\n";
  367.     for (j=0;j<ulChromosomeLength;j++)
  368.     {
  369.         *pOut<<pdBestChromosome[j];
  370.         *pOut<<"\t";
  371.     }
  372.     *pOut<<"\n";
  373.     pOut->close();
  374.     delete pOut;
  375.     return 1;
  376. }
  377.  
  378. int CGA::Load(const char * const psFilename)
  379. {
  380.     //And load it!
  381.     ifstream *pIn=new ifstream(psFilename,ios::nocreate);
  382.     unsigned long i,j;
  383.     if(!pIn || !pIn->is_open())
  384.     {
  385.         return 0;
  386.     }
  387.  
  388.     //Free up memory used by the GA as it is now
  389.     DeallocateMemory();
  390.  
  391.     *pIn>>ulPopulationSize;
  392.     *pIn>>ulChromosomeLength;
  393.  
  394.     //Allocate memory required to store the new GA that is about to be loaded
  395.     AllocateMemory();
  396.     *pIn>>dMutationRate;
  397.     *pIn>>dCrossoverRate;
  398.     *pIn>>ulIteration;
  399.     *pIn>>ulWorkingChromosome;
  400.     for (i=0;i<ulChromosomeLength;i++)
  401.     {
  402.         *pIn>>pnGeneTypes[i];
  403.     }
  404.     for (i=0;i<ulPopulationSize;i++)
  405.     {
  406.         for (j=0;j<ulChromosomeLength;j++)
  407.         {
  408.             *pIn>>ppdGenes[i][j];
  409.         }
  410.         *pIn>>pdFitnesses[i];
  411.     }
  412.     *pIn>>dBestFitness;
  413.     for (j=0;j<ulChromosomeLength;j++)
  414.     {
  415.         *pIn>>pdBestChromosome[j];
  416.     }
  417.     pIn->close();
  418.     delete pIn;
  419.     return 1;
  420. }
  421.